﻿
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Xml.Linq;


namespace BoilenEditor.Primitives {

    [DebuggerDisplay( "ProjectData: FileCount={TemplateFiles.Count}; ProjectDirectory={ProjectDirectory}" )]
    public partial class ProjectData {

        public ProjectData( string filePath )
            : this( filePath, Path.GetDirectoryName( filePath ), null ) {
        }

        partial void InitializeInstance( ) {
            var templateFiles = Ex.GetFiles( this.ProjectDirectory, "*.tt" )
                .Select( path => new FileData( path, this.ProjectDirectory, this ) );
            this.TemplateFiles.AddRange( templateFiles );
        }


        /// <summary>Gets the directory the C# project build files are saved to.</summary>
        public string GetBinDirectory( ) {
            return GetBinDirectory( this.FilePath, this.ProjectDirectory );
        }

        /// <summary>Gets the collection of Boilen template files under the project directory.</summary>
        public IEnumerable<FileData> BoilenFiles {
            get { return this.TemplateFiles.Where( file => file.IsBoilenFile ); }
        }


        protected override string GetDisplayName( string path, string rootDirectory ) {
            return Path.GetFileName( path );
        }

        private static string GetBinDirectory( string path, string rootDirectory ) {
            XDocument project = XDocument.Load( path );

            string nmspace = project.Root.Name.NamespaceName;
            XName propertyGroupElementName = XName.Get( "PropertyGroup", nmspace );
            XName outputPathElementName = XName.Get( "OutputPath", nmspace );

            IEnumerable<string> binDirectories =
                from propertyGroup in project.Root.Elements( propertyGroupElementName )
                let binElement = propertyGroup.Element( outputPathElementName )
                let condition = propertyGroup.Attribute( "Condition" )
                where binElement.HasValue( )
                   && condition.HasValue( )
                   && (condition.Value.Contains( "Debug" )
                    || condition.Value.Contains( "Release" ))
                select Path.GetFullPath( Path.Combine( rootDirectory, binElement.Value ) );

            return binDirectories
                .Where( Directory.Exists )
                .OrderByDescending( GetDirectoryLastWriteTime )
                .FirstOrDefault( )
              ?? binDirectories.First( );
        }

        private static long GetDirectoryLastWriteTime( string directory ) {
            var files = Directory.GetFiles( directory, "*.dll", SearchOption.TopDirectoryOnly );
            return files.Length > 0
                 ? files.Select( File.GetLastWriteTime ).Max( time => time.Ticks )
                 : 0;
        }

    }

}
